/**
 *  Copyright (C) 2008-2013  Telosys project org. ( http://www.telosys.org/ )
 *
 *  Licensed under the GNU LESSER GENERAL PUBLIC LICENSE, Version 3.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *          http://www.gnu.org/licenses/lgpl.html
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package org.telosys.common.dataset;

import java.util.Comparator;

import org.telosys.common.TelosysRuntimeException;

/**
 * Standard comparer for DataRow ( Comparator implementation )
 * 
 * @author Laurent GUERIN
 *  
 */
public class DataRowComparer implements Comparator<DataRow>
{
    public final static boolean IGNORE_CASE        = true;

    public final static boolean DO_NOT_IGNORE_CASE = false;

    public final static boolean DESC               = true;

    public final static boolean ASC                = false;

    private int                 _iCol              = -1;

    private boolean             _bDescendingOrder  = false;

    private boolean             _bIgnoreCase       = false;

    /**
     * Constructor
     * @param iCol the column to use for comparison 
     * @param bDescendingOrder descending order if flag is true
     * @param bIgnoreCase ignore case flag ( used only to compare strings )
     */
    public DataRowComparer(int iCol, boolean bDescendingOrder, boolean bIgnoreCase)
    {
        super();
        _iCol = iCol;
        _bDescendingOrder = bDescendingOrder;
        _bIgnoreCase = bIgnoreCase;
    }

    /**
     * Compare two field values
     * 
     * @param oValue1
     * @param oValue2
     * @return
     */
	@SuppressWarnings("unchecked")
    private int compareFieldValues(Object oValue1, Object oValue2)
    {
        if (oValue1 == null && oValue2 == null)
        {
            return 0; // oValue1 = oValue2
        }
        if (oValue1 == null) // oValue1 is null and oValue2 is not null
        {
            return -1; // oValue1 < oValue2
        }
        if (oValue2 == null) // oValue1 is null and oValue2 is not null
        {
            return +1; // oValue1 > oValue2
        }

        if (oValue1 instanceof String && oValue2 instanceof String)
        {
            return compareStrings((String) oValue1, (String) oValue2);
        }
        else if (oValue1 instanceof Comparable && oValue2 instanceof Comparable)
        {
        	// Unchecked cast
            return compareObjects((Comparable<Object>) oValue1, (Comparable<Object>) oValue2);
        }
        else
        {
            throw new TelosysRuntimeException("sort comparer : object to compare is not comparable ");            
        }
    }

    /**
     * Compares String objects with or whithout case sensitivity
     * 
     * @param s1
     * @param s2
     * @return
     */
    private int compareStrings(String s1, String s2)
    {
        if (_bIgnoreCase)
        {
            return s1.compareToIgnoreCase(s2);
        }
        else
        {
            return s1.compareTo(s2);
        }
    }

    /**
     * Compare generic Comparable objects
     * 
     * @param obj1
     * @param obj2
     * @return
     */
    private int compareObjects(Comparable<Object> obj1, Comparable<Object> obj2)
    {
        return obj1.compareTo(obj2);
    }

    /**
     * Compares objects using ASCENDING ORDER
     * @param obj1
     * @param obj2
     * @return
     */
    private int compareASC(Object obj1, Object obj2) 
    {
        //--- Check parameters ( cannot happened ? )
        if (obj1 == null && obj2 == null)
        {
            return 0; // obj1 == obj2
        }
        if (obj1 == null)
        {
            return -1; // obj1 < obj2
        }
        if (obj2 == null)
        {
            return +1; // obj1 > obj2
        }

        //--- Compare the given DataRows
        DataRow dr1 = null ;
        DataRow dr2 = null ;
        try {
	        dr1 = (DataRow) obj1 ;
	        dr2 = (DataRow) obj2 ;
        } catch ( Exception e ) {
            String s = "("+obj1.getClass().getName() +","+ obj2.getClass().getName()+")" ;
            throw new TelosysRuntimeException("DataSet sort : DataRowComparer : cannot cast to DataRow " + s );
        }
        
        
        //--- Get field values using reflection
        Object oFieldValue1 = dr1.getObject(_iCol);
        Object oFieldValue2 = dr2.getObject(_iCol);

        //--- Compare the 2 field values
        return compareFieldValues(oFieldValue1, oFieldValue2);
    }
    
    /* (non-Javadoc)
     * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
     */
    //public int compare(Object obj1, Object obj2)
    public int compare(DataRow obj1, DataRow obj2)
    {
        //--- Compare in standard ascending order
        int iRet = compareASC(obj1, obj2);
        if ( _bDescendingOrder ) 
        {
            //--- Reverse result 
            if ( iRet > 0 ) 
            {
                return -1 ;
            }
            if ( iRet < 0 ) 
            {
                return +1 ;
            }
            return iRet ;
        }
        else
        {
            //--- Keep the standard ascending result 
            return iRet ;            
        }
    }
}